package service

import (
	"context"
	"encoding/json"
	"io"
	"net/http"
	"time"

	"open/internal/model"
	"open/internal/model/event"
	"open/internal/model/field"
	"open/internal/types"
	"open/pkg/alipay"
)

// CommitAlipayMini 提交支付宝小程序
func (s *Service) CommitAlipayMini(ctx context.Context, appID string, biz json.RawMessage) error {
	// step1: 提交代码
	req := alipay.UploadVersionBiz{}
	var versionDesc string
	if err := json.Unmarshal(biz, &struct {
		*alipay.UploadVersionBiz
		VersionDesc *string `json:"version_desc"`
	}{&req, &versionDesc}); err != nil {
		return err
	}
	err := s.dao.CommitAlipayMini(ctx, appID, &req)
	if err != nil {
		if alipayErr, ok := err.(*alipay.ErrorResponse); ok {
			if alipayErr.SubCode == "VERSION_HAS_EXISTED" {
				err = nil
			}
		}
	}
	if err != nil {
		return err
	}
	// step2: 设置体验版
	_ = s.dao.CreateAlipayMiniExperience(ctx, appID,
		&alipay.CreateExperienceBiz{AppVersion: req.AppVersion, BundleID: req.BundleID})

	if err := s.dao.Transaction(ctx, func(ctx context.Context) error {
		appVersion, err := s.dao.GetAppVersion(ctx, appID, types.Alipay)
		if err != nil {
			return err
		}
		jobData, _ := json.Marshal(&alipay.ApplyVersionAuditBiz{
			AppVersion:  appVersion.AuditVersion,
			VersionDesc: versionDesc,
			RegionType:  "CHINA",
		})
		// Step3: 新建提交审核任务
		schedule := &model.Schedule{
			RefID:     appVersion.ID,
			JobType:   types.TaskCommitAudit,
			JobData:   field.JSON(jobData),
			JobStatus: types.ScheduleTaskInit,
		}
		if err := s.dao.CreateSchedule(ctx, schedule); err != nil {
			return err
		}
		// Step4: 发送事件
		if err := s.dao.TxSend(ctx, event.TaskCommitAudit{
			AppID:     appID,
			Platform:  types.Alipay,
			JobID:     schedule.ID,
			Biz:       jobData,
			Timestamp: time.Now().Unix(),
		}); err != nil {
			return err
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}

// CommitAuditAlipayMini 提交支付宝小程序审核
func (s *Service) CommitAuditAlipayMini(ctx context.Context, appID string, biz json.RawMessage) error {
	alipayMiniApp, err := s.dao.GetAlipayMiniApp(ctx, appID)
	if err != nil {
		return err
	}
	if alipayMiniApp.AppName == "" {
		return s.innerRejectWithReason(ctx, appID, types.Wechat, "请先完善小程序信息再提交审核")
	}
	var LicensePic, OutDoorPic, SpecialLicensePic, AppLogo io.ReadCloser
	LicensePic, err = fetchImage(alipayMiniApp.LicensePic)
	if err != nil {
		return err
	}
	defer LicensePic.Close()
	OutDoorPic, err = fetchImage(alipayMiniApp.OutDoorPic)
	if err != nil {
		return err
	}
	defer OutDoorPic.Close()
	SpecialLicensePic, err = fetchImage(alipayMiniApp.SpecialLicensePic)
	if err != nil {
		return err
	}
	AppLogo, err = fetchImage(alipayMiniApp.AppLogo)
	if err != nil {
		return err
	}
	defer AppLogo.Close()

	reqBiz := alipay.ApplyVersionAuditBiz{
		LicenseName: alipayMiniApp.LicenseName,
		FirstLicensePic: &alipay.File{
			Name:    alipayMiniApp.LicensePic,
			Content: LicensePic,
		},
		LicenseValidDate: alipayMiniApp.LicenseValidDate,
		OutDoorPic: &alipay.File{
			Name:    alipayMiniApp.OutDoorPic,
			Content: OutDoorPic,
		},
		AppSlogan: alipayMiniApp.AppSlogan,
		AppLogo: &alipay.File{
			Name:    alipayMiniApp.AppLogo,
			Content: AppLogo,
		},
		AppDesc:         alipayMiniApp.AppDesc,
		ServicePhone:    alipayMiniApp.ServicePhone,
		LicenseNo:       alipayMiniApp.LicenseNo,
		MiniCategoryIDs: alipayMiniApp.MiniCategoryIDs,
		FirstSpecialLicensePic: &alipay.File{
			Name:    alipayMiniApp.SpecialLicensePic,
			Content: SpecialLicensePic,
		},
	}

	// 未上架过应用才可以修改app_name app_english_name
	appVersion, err := s.dao.GetAppVersion(ctx, appID, types.Alipay)
	if err != nil {
		return err
	}
	if appVersion.ReleaseVersion == "" {
		reqBiz.AppName = alipayMiniApp.AppName
		reqBiz.AppEnglishName = alipayMiniApp.AppEnglishName
	}
	if err = json.Unmarshal(biz, &reqBiz); err != nil {
		return err
	}
	if err := s.dao.CommitAuditAlipayMini(ctx, appID, reqBiz); err != nil {
		return err
	}
	if err := s.dao.Transaction(ctx, func(ctx context.Context) error {
		appVersion, err := s.dao.LockAppVersion(ctx, appID, types.Alipay)
		if err != nil {
			return err
		}
		appVersion.Stage = types.StageAuditing
		if err = s.dao.SaveAppVersion(ctx, appVersion); err != nil {
			return err
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}

// fetchImage 抓取图片字节流
func fetchImage(url string) (io.ReadCloser, error) {
	if url == "" {
		return nil, nil
	}
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	return resp.Body, nil
}

// ReleaseAlipayMini 发布支付宝小程序
func (s *Service) ReleaseAlipayMini(ctx context.Context, appID string) error {
	appVersion, err := s.dao.GetAppVersion(ctx, appID, types.Alipay)
	if err != nil {
		return err
	}
	biz := alipay.OnlineVersionBiz{
		AppVersion: appVersion.AuditVersion,
		BundleID:   "com.alipay.alipaywallet",
	}
	if err := s.dao.ReleaseAlipayMini(ctx, appID, biz); err != nil {
		return err
	}
	if err := s.dao.Transaction(ctx, func(ctx context.Context) error {
		appVersion, err := s.dao.LockAppVersion(ctx, appID, types.Alipay)
		if err != nil {
			return err
		}
		appVersion.Stage = types.StageReleased
		appVersion.Status = types.StageReleased
		appVersion.AuditVersion = ""
		appVersion.ReleaseVersion = appVersion.AuditVersion
		if err = s.dao.SaveAppVersion(ctx, appVersion); err != nil {
			return err
		}
		if err = s.dao.CreateVersionLog(ctx, &model.MiniAppVersionLog{
			VersionID: appVersion.ID,
			Version:   appVersion.ReleaseVersion,
		}); err != nil {
			return err
		}
		return nil
	}); err != nil {
		return err
	}
	return nil

}

// UpdateAlipayMiniStatus 更新支付宝小程序状态
func (s *Service) UpdateAlipayMiniStatus(ctx context.Context, appID string) error {
	appVersion, err := s.dao.GetAppVersion(ctx, appID, types.Alipay)
	if err != nil {
		return err
	}
	biz := alipay.QueryVersionDetailBiz{
		AppVersion: appVersion.AuditVersion,
		BundleID:   "com.alipay.alipaywallet",
	}
	detail, err := s.dao.GetAlipayVersionDetail(ctx, appID, biz)
	if err != nil {
		return err
	}
	var reason, stage, status string
	reason = detail.RejectReason
	switch detail.Status {
	case "AUDITING":
		stage = types.StageAuditing
		status = types.StatusAuditing
	case "WAIT_RELEASE":
		stage = types.StageWaitRelease
		status = types.StatusAuditing
		alipayMiniapp, err := s.dao.GetAlipayMiniApp(ctx, appID)
		if err != nil {
			return err
		}
		// 过审核后更新新的小程序资料
		alipayMiniapp.Name = detail.AppName
		alipayMiniapp.Slogan = detail.AppSlogan
		alipayMiniapp.Logo = detail.AppLogo
		if err = s.dao.SaveAlipayMiniApp(ctx, alipayMiniapp); err != nil {
			return err
		}
	case "AUDIT_REJECT":
		stage = types.StageAuditReject
		status = types.StatusReject
		// 退回到开发版 && 删除开发版本已便于重新提交
		if err = s.dao.CancelAlipayVersionAudited(ctx, appID, alipay.CancelVersionAuditedBiz{
			AppVersion: appVersion.AuditVersion,
			BundleID:   "com.alipay.alipaywallet",
		}); err != nil {
			return err
		}
		if err = s.dao.CreateAlipayMiniExperience(ctx, appID, &alipay.CreateExperienceBiz{
			AppVersion: appVersion.AuditVersion,
			BundleID:   "com.alipay.alipaywallet",
		}); err != nil {
			return err
		}
	case "RELEASE":
		stage = types.StageReleased
		status = types.StatusReleased
	case "INIT":
		stage = types.StageCommitted
		status = types.StatusAuditing
	}
	if err := s.dao.Transaction(ctx, func(ctx context.Context) error {
		appVersion, err := s.dao.LockAppVersion(ctx, appID, types.Alipay)
		if err != nil {
			return err
		}
		appVersion.Stage = stage
		appVersion.Status = status
		appVersion.RejectReason = reason
		if err = s.dao.SaveAppVersion(ctx, appVersion); err != nil {
			return err
		}
		return nil
	}); err != nil {
		return err
	}
	return nil

}
